package com.service.user;

import com.domain.HttpResponse;
import com.domain.ex.BizException;
import com.domain.ex.Codes;
import com.domain.myenum.RoleEnum;
import com.domain.page.Paginator;
import com.dto.UserExtDto;
import com.dto.UserSortDto;
import com.dto.statistic.ConsumptionWaterDto;
import com.dto.statistic.StatisticOutputDto;
import com.dto.statistic.UserStatisticDto;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.handler.email.Email;
import com.handler.email.EmailHandler;
import com.mapper.self.CompanyMapper;
import com.mapper.self.IncomeWaterMapper;
import com.mapper.self.OrderMapper;
import com.pojo.ShCompany;
import com.pojo.ShIncomeWater;
import com.utils.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Huoyunren on 2016/1/27.
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private CompanyMapper companyMapper;
    @Autowired
    private Gson gson;
    @Autowired
    private EmailHandler emailHandler;
    @Autowired
    private IncomeWaterMapper incomeWaterMapper;
    @Autowired
    private OrderMapper orderMapper;

    // - 注册
    @Override
    public Object register(String email, String referralCode) {
        if (!ValidatorUtils.validatorEmail(email)) {
            throw BizException.create(Codes.SystemDeclare, "邮箱格式错误");
        }
        ShCompany shCompany = companyMapper.queryByEmail(email);
        if (shCompany != null) {
            throw BizException.create(Codes.SystemDeclare, "邮箱已被注册");
        }
        List<String> codes = companyMapper.queryCodes();
        if (StringUtils.isNotBlank(referralCode)) {
            // - 有推荐人邀请码
            if (!isReferralCodeExists(referralCode, codes)) {
                throw BizException.create(Codes.SystemDeclare, "邀请码不存在");
            }
        }
        String password = RandomUtils.random4();
        String code = getUniqueUnUsedReferralCode(RandomUtils.random6(), codes);
        companyMapper.register(email, EncryptUtils.md5(password), DateUtils.currentDate(), code, referralCode);
        // - 异步发邮件 - 发送初始密码
        Email e = new Email();
        String[] to = new String[1];
        to[0] = email;
        e.setTo(to);
        e.setSubject("注册成功");
        e.setEnableHtml(Boolean.FALSE);
        StringBuffer sb = new StringBuffer();
        sb.append("初始密码：" + password + "\n非常感谢成为劉員外会员.请及时更新密码!");
        sb.append("\n");
        sb.append("官方网址：www.liuyuanwai.cn");
        e.setContent(sb.toString());
        emailHandler.asyncSendMail(e);
        return gson.toJson(HttpResponse.create(Codes.OK));
    }


    // - 得到数据库没有的推荐码
    public String getUniqueUnUsedReferralCode(String referralCode, List<String> codes) {
        if (CollectionUtils.isEmpty(codes)) {
            return referralCode;
        }
        if (!codes.contains(referralCode)) {
            // - 该推荐码没有被使用
            return referralCode;
        }
        return getUniqueUnUsedReferralCode(RandomUtils.random6(), codes);
    }

    public boolean isReferralCodeExists(String referralCode, List<String> codes) {
        if (CollectionUtils.isEmpty(codes)) {
            return Boolean.FALSE;
        }
        if (codes.contains(referralCode)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    // - 登录
    @Override
    public Object login(String email, String password) {

        ShCompany shCompany = companyMapper.queryByEmail(email);
        if (shCompany == null) {
            throw BizException.create(Codes.LoginError, "邮箱不存在");
        }
        shCompany = companyMapper.login(email, EncryptUtils.md5(password));
        if (shCompany == null) {
            throw BizException.create(Codes.LoginError, "帐号密码验证失败");
        }
        sessionLoginInfo(shCompany);
        return gson.toJson(HttpResponse.create(Codes.OK, "", shCompany));
    }

    // - 将户相关信息写到session
    private void sessionLoginInfo(ShCompany shCompany) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes()).getRequest();
        // - 将用户邮箱存到session
        request.getSession().setAttribute("email", shCompany.getEmail());
        // - 将用户角色存入session
        request.getSession().setAttribute("roleId", shCompany.getRole());
        // - 将用户LOGO存入session
        request.getSession().setAttribute("logo", shCompany.getLogo());
        // - 将用户NAME存入session
        request.getSession().setAttribute("name", shCompany.getName());
    }

    @Override
    public Object fakeLogin(String email, String login) {
        if (StringUtils.isBlank(email) || StringUtils.isBlank(login)) {
            return gson.toJson(HttpResponse.create(Codes.LoginError));
        }
        ShCompany company = companyMapper.queryByEmail(email);
        if (company == null) {
            return gson.toJson(HttpResponse.create(Codes.LoginError));
        }
        sessionLoginInfo(company);
        return gson.toJson(HttpResponse.create(Codes.OK, "", company));
    }

    /**
     * 查询企业资料
     *
     * @param email
     * @return
     */
    @Override
    public ShCompany info(String email) {

        ShCompany shCompany = companyMapper.queryByEmail(email);
        if (shCompany == null) {
            throw BizException.create(Codes.SystemDeclare, "没有查询到用户");
        }
        shCompany.setRole(RoleEnum.queryStatusVal(Integer.valueOf(shCompany.getRole())));
        if (StringUtils.isBlank(shCompany.getRemark())){
            shCompany.setRemark("简介");
        }
        return shCompany;
    }

    /**
     * 查询企业资料.只读
     *
     * @param email
     * @return
     */
    @Override
    public UserExtDto queryInfo(String email) {
        UserExtDto userExtDto = new UserExtDto();
        ShCompany shCompany = companyMapper.queryUserExtByEmail(email);
        if (shCompany == null) {
            return userExtDto;
        }
        BeanUtils.copyProperties(shCompany, userExtDto);
        BigDecimal income = incomeWaterMapper.calculateMyIncome(email, null);
        if (income == null) {
            income = BigDecimal.ZERO.setScale(2);
        }
        userExtDto.setIncome(income);
        return userExtDto;
    }

    /**
     * 更新资料
     *
     * @param shCompany
     * @return
     */
    @Override
    public Object updateInfo(ShCompany shCompany) {

        if (shCompany == null) {
            throw BizException.create(Codes.ParamError, "空参数");
        }

        if (StringUtils.isBlank(shCompany.getPhone())) {
            throw BizException.create(Codes.ParamError, "请填写手机号");
        }
        if (!ValidatorUtils.validatorMobile(shCompany.getPhone())) {
            throw BizException.create(Codes.ParamError, "手机号格式错误");
        }

        shCompany.setDeleted(0);
        shCompany.setCheckStatus(0);
        shCompany.setUpdatetime(new Date());
        // - 修改资料后审核状态改为等待审核
        shCompany.setCheckStatus(0);
        companyMapper.saveOrUpdate(shCompany);
        // - 更新session数据
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.getSession().setAttribute("name", shCompany.getName());
        return gson.toJson(HttpResponse.OK());
    }


    /**
     * 更新密码
     *
     * @param password
     * @param email
     * @return
     */
    @Override
    public Object updatePassword(String password, String email, String oldPassword) {
        ShCompany shCompany = companyMapper.login(email, EncryptUtils.md5(oldPassword));
        if (shCompany == null) {
            throw BizException.create(Codes.SystemDeclare, "旧密码验证失败");
        }
        companyMapper.updatePassword(EncryptUtils.md5(password), email, EncryptUtils.md5(oldPassword), new Date());
        return gson.toJson(HttpResponse.OK());
    }


    /**
     * 分页查询所有用户
     *
     * @param page
     * @param limit
     * @return
     */
    @Override
    public Object list(int page, int limit, String queryKey, String role) {
        if (page > 0) {
            page = page - 1;
        }
        if (StringUtils.isBlank(role)) {
            role = null;
        }
        UserSortDto userSortDto = new UserSortDto();
        int count = companyMapper.count(queryKey,role);
        List<ShCompany> companies = companyMapper.list(page * limit, limit, queryKey, role);
        for (ShCompany shCompany : companies) {
            shCompany.setRole(RoleEnum.queryStatusVal(Integer.valueOf(shCompany.getRole())));
            if (StringUtils.isBlank(shCompany.getRemark())){
                shCompany.setRemark("简介");
            }
        }
        Paginator paginator = Paginator.instance(count, companies);
        paginator.setPage(page + 1);
        paginator.setLimit(limit);
        userSortDto.setPaginator(paginator);
        return userSortDto;
    }

    /**
     * 审核
     *
     * @param ids    审核用户ID集合，逗号分割
     * @param status 审核结果【1：审核通过，2：审核失败】
     * @return
     */
    @Override
    public Object check(String ids, Integer status) {
        if (StringUtils.isBlank(ids)) {
            return HttpResponse.OK();
        }
        companyMapper.check(ids.split(","), status);
        return HttpResponse.OK();
    }


    /**
     * 找回密码，用一个随机的四位数作为新密码
     *
     * @param email
     * @return
     */
    @Override
    public Object findPassword(String email) {

        boolean flag = ValidatorUtils.validatorEmail(email);
        if (!flag) {
            throw BizException.create(Codes.ParamError, "邮箱格式错误");
        }
        ShCompany shCompany = companyMapper.queryByEmail(email);
        if (shCompany == null) {
            throw BizException.create(Codes.ParamError, "邮箱不存在");
        }

        String password = RandomUtils.random4();
        companyMapper.updatePassword(EncryptUtils.md5(password), email, null, new Date());

        // - 异步发邮件
        Email e = new Email();
        String[] to = new String[1];
        to[0] = email;
        e.setTo(to);
        e.setSubject("密码找回");
        e.setContent("新密码:" + password + ".请及时更新密码!");
        e.setEnableHtml(Boolean.FALSE);
        emailHandler.asyncSendMail(e);
        return gson.toJson(HttpResponse.create(Codes.OK, "密码已发送至邮箱"));
    }

    @Override
    public Object updateUserRole(String email, Integer roleId) {
        companyMapper.updateUserRole(email, roleId);
        return HttpResponse.OK();
    }


    @Override
    public Object updateLogo(String logo, String email) {
        companyMapper.updateLogo(logo, email);
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        request.getSession().setAttribute("logo", logo);
        return HttpResponse.OK();
    }

    @Override
    public void updateInCount() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object email = request.getSession().getAttribute("email");
        if (email != null) {
            companyMapper.incrInCount(email.toString());
        }
    }

    @Override
    public Object warterStatistic() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Object email = request.getSession().getAttribute("email");
        Map<String/* day */, BigDecimal/* amount */> platMap = Maps.newHashMap();
        Map<String/* day */, BigDecimal/* amount */> selfMap = Maps.newHashMap();
        List<String> xAixs = Lists.newArrayList();
        // - 平台流水
        List<BigDecimal> platWateryAixs = Lists.newArrayList();
        // - 我的流水
        List<BigDecimal> selfWateryAixs = Lists.newArrayList();
        int curDay = DateUtils.getDay();
        int j = 0;
        int lastDayOfLastMonth = DateUtils.getLastDayOfLastMonth();
        for (int i = curDay - 9; i <= curDay; i++) {
            j = i;
            if (j <= 0) {
                j += lastDayOfLastMonth;
            }
            xAixs.add(String.valueOf(j));
            platMap.put(String.valueOf(j), BigDecimal.ZERO);
            selfMap.put(String.valueOf(j), BigDecimal.ZERO);
        }
        List<StatisticOutputDto> platWater = companyMapper.searchConsumptionWarter(null);
        if (!CollectionUtils.isEmpty(platWater)) {
            for (StatisticOutputDto statisticOutputDto : platWater) {
                platMap.put(statisticOutputDto.getName(), statisticOutputDto.getData());
            }
            for (String x : xAixs) {
                platWateryAixs.add(platMap.get(x));
            }
        } else {
            for (int i = curDay - 9; i <= curDay; i++) {
                platWateryAixs.add(BigDecimal.ZERO);
            }
        }
        List<StatisticOutputDto> selfWater = null;
        if (email != null) {
            selfWater = companyMapper.searchConsumptionWarter(email.toString());
            if (!CollectionUtils.isEmpty(selfWater)) {
                for (StatisticOutputDto statisticOutputDto : selfWater) {
                    selfMap.put(statisticOutputDto.getName(), statisticOutputDto.getData());
                }
                for (String x : xAixs) {
                    selfWateryAixs.add(selfMap.get(x));
                }
            } else {
                for (int i = curDay - 9; i <= curDay; i++) {
                    selfWateryAixs.add(BigDecimal.ZERO);
                }
            }
        }
        ConsumptionWaterDto consumptionWaterDto = new ConsumptionWaterDto();
        consumptionWaterDto.setxAixs(xAixs);
        consumptionWaterDto.setPlatWateryAixs(platWateryAixs);
        consumptionWaterDto.setSelfWateryAixs(selfWateryAixs);
        return consumptionWaterDto;
    }

    @Override
    public Object userStatistic() {
        List<StatisticOutputDto> list = companyMapper.userStatistic();
        UserStatisticDto dto = new UserStatisticDto();
        List<String> xAixs = Lists.newArrayList();
        List<Integer> yAixs = Lists.newArrayList();
        Map<String, Integer> map = Maps.newHashMap();
        int curDay = DateUtils.getDay();
        int j = 0;
        int lastDayOfLastMonth = DateUtils.getLastDayOfLastMonth();
        for (int i = curDay - 9; i <= curDay; i++) {
            j = i;
            if (j <= 0) {
                j += lastDayOfLastMonth;
            }
            xAixs.add(String.valueOf(j));
            map.put(String.valueOf(j), 0);
        }
        if (!CollectionUtils.isEmpty(list)) {
            for (StatisticOutputDto outputDto : list) {
                map.put(outputDto.getName(), Integer.parseInt(outputDto.getData().toString()));
            }
        }
        int max = companyMapper.count(null,null);
        int min = Collections.min(map.values());
        for (String xAix : xAixs) {
            yAixs.add(map.get(xAix));
        }
        if (yAixs.get(0) < min) {
            yAixs.set(0, min);
        }
        if (yAixs.get(yAixs.size() - 1) < max) {
            yAixs.set(yAixs.size() - 1, max);
        }
        for (int i = 0; i < yAixs.size() - 1; i++) {
            if (yAixs.get(i + 1) < yAixs.get(i)) {
                yAixs.set(i + 1, yAixs.get(i));
            }
        }
        for (int i = yAixs.size(); i > 0; i--) {
            if (yAixs.get(i - 1) == 0) {
                yAixs.set(i - 1, yAixs.get(i));
            }
        }
        dto.setxAixs(xAixs);
        dto.setyAixs(yAixs);
        return dto;
    }

    @Override
    public Object platStatistic(String shopEmail) {
        Map<String/* day */, BigDecimal/* amount */> platWaterMap = Maps.newHashMap();
        Map<String/* day */, BigDecimal/* amount */> platCostMap = Maps.newHashMap();
        Map<String/* day */, BigDecimal/* amount */> platIncomeMap = Maps.newHashMap();
        List<String> xAixs = Lists.newArrayList();
        // - 平台流水
        List<BigDecimal> platWateryAixs = Lists.newArrayList();
        // - 平台成本
        List<BigDecimal> platCostyAixs = Lists.newArrayList();
        // - 平台收益
        List<BigDecimal> platIncomeyAixs = Lists.newArrayList();
        int curDay = DateUtils.getDay();
        int j = 0;
        int lastDayOfLastMonth = DateUtils.getLastDayOfLastMonth();
        for (int i = curDay - 9; i <= curDay; i++) {
            j = i;
            if (j <= 0) {
                j += lastDayOfLastMonth;
            }
            xAixs.add(String.valueOf(j));
            platWaterMap.put(String.valueOf(j), BigDecimal.ZERO);
            platCostMap.put(String.valueOf(j), BigDecimal.ZERO);
            platIncomeMap.put(String.valueOf(j), BigDecimal.ZERO);
        }
        List<StatisticOutputDto> platData = null;
        if (StringUtils.isBlank(shopEmail)) {
            // - 平台消费流水
            platData = companyMapper.searchConsumptionWarter(null);
        } else {
            // - 门店消费流水
            platData = companyMapper.searchShopWarter(shopEmail);
        }
        if (!CollectionUtils.isEmpty(platData)) {
            for (StatisticOutputDto statisticOutputDto : platData) {
                platWaterMap.put(statisticOutputDto.getName(), statisticOutputDto.getData());
                platCostMap.put(statisticOutputDto.getName(), statisticOutputDto.getData1());
                platIncomeMap.put(statisticOutputDto.getName(), statisticOutputDto.getData().subtract(statisticOutputDto.getData1()));
            }
            for (String x : xAixs) {
                platWateryAixs.add(platWaterMap.get(x));
                platCostyAixs.add(platCostMap.get(x));
                platIncomeyAixs.add(platIncomeMap.get(x));
            }
        } else {
            for (int i = curDay - 9; i <= curDay; i++) {
                platWateryAixs.add(BigDecimal.ZERO);
                platCostyAixs.add(BigDecimal.ZERO);
                platIncomeyAixs.add(BigDecimal.ZERO);
            }
        }
        ConsumptionWaterDto consumptionWaterDto = new ConsumptionWaterDto();
        consumptionWaterDto.setxAixs(xAixs);
        consumptionWaterDto.setPlatWateryAixs(platWateryAixs);
        consumptionWaterDto.setPlatCostyAixs(platCostyAixs);
        consumptionWaterDto.setPlatIncomeyAixs(platIncomeyAixs);
        // - 计算平台总流水和总收益
        BigDecimal water = BigDecimal.ZERO;
        BigDecimal cost = BigDecimal.ZERO;
        if (StringUtils.isBlank(shopEmail)) {
            // - 平台
            water = orderMapper.waterStatistic();
            cost = orderMapper.costStatistic();
        } else {
            // - 门店
            water = orderMapper.shopWaterStatistic(shopEmail);
            cost = orderMapper.shopCostStatistic(shopEmail);
        }
        if (water == null) {
            water = BigDecimal.ZERO;
        }
        if (cost == null) {
            cost = BigDecimal.ZERO;
        }
        consumptionWaterDto.setPlatWater(water.setScale(2, BigDecimal.ROUND_HALF_UP));
        consumptionWaterDto.setPlatCost(cost.setScale(2, BigDecimal.ROUND_HALF_UP));
        consumptionWaterDto.setPlatIncome(consumptionWaterDto.getPlatWater().subtract(consumptionWaterDto.getPlatCost()));
        return consumptionWaterDto;
    }

    @Override
    public BigDecimal incomeStatistic(String email, Integer deleted) {
        if (StringUtils.isBlank(email)) {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            Object obj = request.getSession().getAttribute("email");
            if (obj != null) {
                email = obj.toString();
            }
        }
        BigDecimal income = companyMapper.queryByEmail(email).getInCount();
        if (income == null) {
            return BigDecimal.ZERO;
        }
        return income;
    }

    @Override
    public BigDecimal incomeSingleStatistic(String buyerEmail, String shopEmail) {
        BigDecimal income = incomeWaterMapper.calculateSingleIncome(buyerEmail, shopEmail);
        if (income == null) {
            income = BigDecimal.ZERO;
        }
        return income;
    }

    @Override
    public Object incomeList(int pageNo, int pageSize, Integer shopId) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String email = null;
        Object obj = request.getSession().getAttribute("email");
        if (obj != null) {
            email = obj.toString();
        }
        if (pageNo > 0) {
            pageNo = pageNo - 1;
        }
        List<ShIncomeWater> list = incomeWaterMapper.list(email, pageNo * pageSize, pageSize, shopId);
        return Paginator.instance(0, list);
    }

    @Override
    public Object incomeListGroupByShop(int pageNo, int pageSize) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String email = null;
        Object obj = request.getSession().getAttribute("email");
        if (obj != null) {
            email = obj.toString();
        }
        if (pageNo > 0) {
            pageNo = pageNo - 1;
        }
        List<ShIncomeWater> list = incomeWaterMapper.listIncomeGroupByShop(email, pageNo * pageSize, pageSize);
        return list;
    }


    @Override
    public Object updateWeixinQrcode(String weixinQrcode, String email) {
        companyMapper.updateWeixinQrcode(weixinQrcode,email);
        return HttpResponse.OK();
    }

    @Override
    public Object updateAlipayQrcode(String alipayQrcode, String email) {
        companyMapper.updateAlipayQrcode(alipayQrcode,email);
        return HttpResponse.OK();
    }

    @Override
    public void validateUserInfoCompleted(String email) {
        ShCompany company = companyMapper.queryByEmail(email);
        if (company == null){
            throw BizException.create(Codes.SystemDeclare, "没有查询到您的资料");
        }
        if (StringUtils.isBlank(company.getName())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:姓名");
        }
        if (StringUtils.isBlank(company.getPhone())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:电话");
        }
        if (StringUtils.isBlank(company.getAddr())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:联系地址");
        }
        if (StringUtils.isBlank(company.getLogo())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:头像");
        }
    }

    @Override
    public void validateUserInfoCompleted(ShCompany company) {
        if (company == null){
            throw BizException.create(Codes.SystemDeclare, "没有查询到您的资料");
        }
        if (StringUtils.isBlank(company.getName())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:姓名");
        }
        if (StringUtils.isBlank(company.getPhone())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:电话");
        }
        if (StringUtils.isBlank(company.getAddr())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:联系地址");
        }
        if (StringUtils.isBlank(company.getLogo())) {
            throw BizException.create(Codes.SystemDeclare, "请完善资料:头像");
        }
    }
}
